﻿using Entity;
using IRepository;
using IService;
using Repository;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace Service
{
    public class NumberingRuleService : INumberingRuleService
    {
        private readonly INumberingRuleRepository _repository;
        private readonly ITargetFormRepository _targetFormRepository;

        public NumberingRuleService(INumberingRuleRepository repository, ITargetFormRepository targetFormRepository)
        {
            _repository = repository ?? throw new ArgumentNullException(nameof(repository));
            _targetFormRepository = targetFormRepository ?? throw new ArgumentNullException(nameof(targetFormRepository));
        }

        /// <summary>
        /// 根据目标表单名称获取最新规则
        /// </summary>
        public NumberingRule GetByTargetFormName(string targetFormName)
        {
            Console.WriteLine($"【Service-GetByTargetFormName】开始，参数: '{targetFormName}'");

            if (string.IsNullOrWhiteSpace(targetFormName))
                throw new ArgumentException("目标表单名称不能为空", nameof(targetFormName));

            // 直接查询数据库获取最新规则，不依赖缓存
            var rule = _repository.GetByTargetFormName(targetFormName);

            if (rule == null)
            {
                string errorMsg = $"未找到目标表单「{targetFormName}」对应的编号规则";
                Console.WriteLine($"【Service-GetByTargetFormName】错误: {errorMsg}");
                throw new KeyNotFoundException(errorMsg);
            }

            Console.WriteLine($"【Service-GetByTargetFormName】成功找到规则: ID={rule.rule_id}, 表单={rule.target_form}");

            // 确保规则参数有效
            rule.step = rule.step <= 0 ? 1 : rule.step;
            rule.serial_number = rule.serial_number <= 0 ? 3 : rule.serial_number;
            rule.max_value = rule.max_value < 0 ? 0 : rule.max_value;

            return rule;
        }

        public NumberingRule GetById(int rule_id)
        {
            if (rule_id <= 0)
                throw new ArgumentOutOfRangeException(nameof(rule_id), "规则ID必须大于0");

            return _repository.GetById(rule_id);
        }

        /// <summary>
        /// 保存规则
        /// </summary>
        public int SaveRule(NumberingRule rule, string currentUser)
        {
            if (rule == null)
                throw new ArgumentNullException(nameof(rule));

            if (string.IsNullOrWhiteSpace(currentUser))
                throw new ArgumentException("当前用户不能为空", nameof(currentUser));

            // 验证步长和流水号位数
            if (rule.step <= 0)
                throw new ArgumentException("步长必须大于0", nameof(rule.step));

            if (rule.serial_number <= 0)
                throw new ArgumentException("流水号位数必须大于0", nameof(rule.serial_number));

            // 新增时检查重复
            if (rule.rule_id == 0)
            {
                var existingRules = GetByConditions(new NumberingRuleQueryParams
                {
                    target_id = rule.target_id,
                    number_prefix = rule.number_prefix
                });

                if (existingRules?.Data?.Count > 0)
                {
                    throw new InvalidOperationException($"已存在相同的目标表单「{rule.target_id}」和编号前缀「{rule.number_prefix}」的规则");
                }
            }

            // 设置操作人信息
            if (rule.rule_id == 0)
            {
                rule.create_by = currentUser;
                rule.Operator = currentUser;
            }
            else
            {
                rule.update_by = currentUser;
                rule.Operator = currentUser;
            }

            return _repository.SaveRule(rule);
        }

        public int GetMaxSerialNumber(string targetForm, string number_prefix)
        {
            if (string.IsNullOrWhiteSpace(targetForm))
                throw new ArgumentException("目标表单不能为空");

            if (string.IsNullOrWhiteSpace(number_prefix))
                throw new ArgumentException("编号前缀不能为空");

            return _repository.GetMaxSerialNumber(targetForm, number_prefix);
        }

        public int UpdateSerialNumber(string targetForm, string number_prefix, int new_serial_number)
        {
            if (string.IsNullOrWhiteSpace(targetForm))
                throw new ArgumentException("目标表单不能为空");

            if (string.IsNullOrWhiteSpace(number_prefix))
                throw new ArgumentException("编号前缀不能为空");

            if (new_serial_number < 0)
                throw new ArgumentOutOfRangeException("流水号不能为负数");

            return _repository.UpdateSerialNumber(targetForm, number_prefix, new_serial_number);
        }
        
        /// <summary>
        /// 基于目标表单名称生成编号
        /// </summary>
        public string GenerateBusinessNumber(string targetFormName, string operatorName)
        {
            
            // 调用重载方法，使用规则默认步长
            return GenerateBusinessNumber(targetFormName, operatorName, null, null);
        }

        /// <summary>
        /// 基于目标表单名称生成编号（临时步长）
        /// </summary>
        public string GenerateBusinessNumber(string targetFormName, string operatorName, int tempStep)
        {
            if (tempStep <= 0)
                throw new ArgumentException("临时步长必须大于0", nameof(tempStep));

            return GenerateBusinessNumber(targetFormName, operatorName, null, tempStep);
        }

        /// <summary>
        /// 基于目标表单名称生成编号（灵活控制）
        /// </summary>
        public string GenerateBusinessNumber(string targetFormName, string operatorName, int? specificSerialNumber, int? tempStep = null)
        {
            if (string.IsNullOrWhiteSpace(targetFormName))
                throw new ArgumentException("目标表单名称不能为空", nameof(targetFormName));

            if (string.IsNullOrWhiteSpace(operatorName))
                throw new ArgumentException("操作人不能为空", nameof(operatorName));

            var rule = GetByTargetFormName(targetFormName);
            int step = tempStep ?? rule.step;
            if (step <= 0)
                throw new InvalidOperationException($"规则步长无效（步长：{step}）");

            int newSerialNumber = specificSerialNumber ?? (rule.max_value + step);
            if (specificSerialNumber.HasValue && specificSerialNumber.Value < 0)
                throw new ArgumentOutOfRangeException(nameof(specificSerialNumber), "指定的流水号不能为负数");

            string datePart = GenerateDatePart(rule);
            string serialPart = newSerialNumber.ToString().PadLeft(rule.serial_number, '0');
            string businessNumber = $"{rule.number_prefix}{datePart}{serialPart}";

            UpdateRuleMaxValue(rule, newSerialNumber, operatorName);
            return businessNumber;
        }

        

        /// <summary>
        /// 基于规则ID生成编号（核心修复方法）
        /// </summary>
        public string GenerateBusinessNumber(int ruleId, string currentUser)
        {
            try
            {
                Console.WriteLine($"【Service-GenerateBusinessNumber】开始生成业务单据号，规则ID: {ruleId}");

                if (ruleId <= 0)
                {
                    throw new ArgumentException("规则ID必须大于0", nameof(ruleId));
                }

                // 1. 按规则ID查询（关键修复：确保用rule_id查询）
                var rule = _repository.GetById(ruleId);
                if (rule == null)
                {
                    throw new KeyNotFoundException($"未找到ID为{ruleId}的编号规则");
                }

                Console.WriteLine($"【Service-GenerateBusinessNumber】找到规则: 前缀={rule.number_prefix}, 目标ID={rule.target_id}");

                // 2. 验证目标表单（可选，确保关联正确）
                var targetForm = _targetFormRepository.GetById(rule.target_id);
                if (targetForm == null)
                {
                    Console.WriteLine($"【警告】规则ID={ruleId}关联的目标表单ID={rule.target_id}不存在，但仍可生成编号");
                    // 不抛出异常，仅警告，避免因目标表单配置问题阻断编号生成
                }

                // 3. 生成编号
                string businessNumber = GenerateNumber(rule, currentUser);
                Console.WriteLine($"【Service-GenerateBusinessNumber】生成业务编号: {businessNumber}");

                return businessNumber;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"【Service-GenerateBusinessNumber】异常: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 生成编号的辅助方法
        /// </summary>
        private string GenerateNumber(NumberingRule rule, string operatorName)
        {
            if (rule == null)
                throw new ArgumentNullException(nameof(rule));

            if (string.IsNullOrWhiteSpace(operatorName))
                throw new ArgumentException("操作人不能为空", nameof(operatorName));

            int newSerialNumber = rule.max_value + rule.step;
            string datePart = GenerateDatePart(rule);
            string serialPart = newSerialNumber.ToString().PadLeft(rule.serial_number, '0');
            string businessNumber = $"{rule.number_prefix}{datePart}{serialPart}";

            UpdateRuleMaxValue(rule, newSerialNumber, operatorName);
            return businessNumber;
        }

        /// <summary>
        /// 更新规则的最大流水号（防并发）
        /// </summary>
        private void UpdateRuleMaxValue(NumberingRule rule, int new_max_value, string operatorName)
        {
            try
            {
                // 开启事务并指定隔离级别
                using (var transaction = _repository.GetDbConnection().BeginTransaction(IsolationLevel.RepeatableRead))
                {
                    try
                    {
                        var ruleWithLock = _repository.GetRuleWithLock(rule.rule_id, transaction); // 传递事务
                        if (ruleWithLock == null)
                            throw new KeyNotFoundException($"规则ID {rule.rule_id} 不存在或已被删除");

                        bool updateSuccess = _repository.UpdateMaxValueAndTime(
                            rule_id: rule.rule_id,
                            newMaxValue: new_max_value,
                            last_generation_time: DateTime.Now,
                            @operator: operatorName,
                            transaction: transaction // 传递事务
                        );

                        if (!updateSuccess)
                            throw new Exception($"更新规则ID {rule.rule_id} 的最大流水号失败");

                        transaction.Commit(); // 提交事务
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback(); // 回滚事务
                        throw new Exception($"更新流水号失败：{ex.Message}", ex);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"更新流水号失败：{ex.Message}", ex);
            }
        }

        /// <summary>
        /// 生成日期部分
        /// </summary>
        private string GenerateDatePart(NumberingRule rule)
        {
            if (string.IsNullOrWhiteSpace(rule.time_rule))
                return DateTime.Now.ToString("yyyyMMdd");

            var date = DateTime.Now;
            var datePart = new System.Text.StringBuilder();

            if (rule.time_rule.Contains("YYYY")) datePart.Append(date.ToString("yyyy"));
            if (rule.time_rule.Contains("MM")) datePart.Append(date.ToString("MM"));
            if (rule.time_rule.Contains("DD")) datePart.Append(date.ToString("dd"));
            if (rule.time_rule.Contains("HH")) datePart.Append(date.ToString("HH"));
            if (rule.time_rule.Contains("mm")) datePart.Append(date.ToString("mm"));
            if (rule.time_rule.Contains("ss")) datePart.Append(date.ToString("ss"));

            return datePart.ToString();
        }

        public List<NumberingRule> GetByIds(List<int> ids)
        {
            if (ids == null || !ids.Any())
                return new List<NumberingRule>();

            return _repository.GetByIds(ids);
        }

        /// <summary>
        /// 同时添加目标表单和编号规则
        /// </summary>
        public int AddTargetAndRule(TargetForm targetForm, NumberingRule numberingRule, string currentUser)
        {
            try
            {
                Console.WriteLine($"【Service-AddTargetAndRule】开始处理，目标表单: {targetForm?.target_form}");

                if (targetForm == null)
                    throw new ArgumentNullException(nameof(targetForm), "目标表单不能为空");
                if (numberingRule == null)
                    throw new ArgumentNullException(nameof(numberingRule), "编号规则不能为空");

                targetForm.is_active = 1;
                targetForm.creation_time = DateTime.Now;

                int newRuleId = _repository.AddTargetAndRule(targetForm, numberingRule);
                Console.WriteLine($"【Service-AddTargetAndRule】添加成功，规则ID: {newRuleId}");
                return newRuleId;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"【Service-AddTargetAndRule】异常: {ex.Message}");
                throw new Exception($"添加目标表单和编号规则失败: {ex.Message}", ex);
            }
        }

        public PaginationResult<NumberingRule> GetByConditions(NumberingRuleQueryParams queryParams)
        {
            queryParams ??= new NumberingRuleQueryParams();
            queryParams.PageIndex = queryParams.PageIndex < 1 ? 1 : queryParams.PageIndex;
            queryParams.PageSize = queryParams.PageSize < 1 || queryParams.PageSize > 100 ? 10 : queryParams.PageSize;

            return _repository.GetByConditions(queryParams);
        }

        public bool DeleteRule(int rule_id, string currentUser)
        {
            if (rule_id <= 0)
                throw new ArgumentOutOfRangeException(nameof(rule_id), "规则ID必须大于0");

            if (string.IsNullOrWhiteSpace(currentUser))
                throw new ArgumentException("当前用户不能为空", nameof(currentUser));

            var rule = _repository.GetById(rule_id);
            if (rule == null || rule.is_delete != 0)
            {
                return false;
            }

            return _repository.DeleteRule(rule_id, currentUser);
        }
        
        public int GetRuleIdByTargetId(int targetId)
        {
            if (targetId <= 0)
                throw new ArgumentOutOfRangeException(nameof(targetId), "目标表单ID必须大于0");

            var rule = _repository.GetByTargetId(targetId);
            if (rule == null)
                throw new KeyNotFoundException($"未找到目标表单ID为 {targetId} 的编号规则");

            return rule.rule_id;
        }

    }
}